#pragma once

#include <cstring>
#include <iostream>  
#include <functional>
#include <thread>
#include <unordered_map>
#include <memory>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>

#include "nocopy.hpp"
#include "Log.hxx"
#include "Common.hpp"
#include "MutiProcess.hxx"
#include "ThreadPoolOnlyOne.hxx"
#include "InetAddr.hxx"
#include "Translate.hpp"


const static int default_backlog = 5;
using namespace myService;

class TcpServer: public nocopy
{
    uint16_t _port;
    int _listensock;
    bool _isRunning;
    std::function<struct sockaddr*(void*)> conv= [](void* addr){
        return (struct sockaddr*)addr;
    };
    using _task_func_t = function<void(int, InetAddr)>;


    std::unordered_map<std::string,_task_func_t> _funcs;
    public:
    TcpServer(uint16_t port)
    :_port(port)
    {

    }

    void Init()
    {
        //1.创建套接字

        //面向字节流的
        _listensock = socket(AF_INET,SOCK_STREAM,0);
        if(_listensock<0)
        {
            lg(Log::MsgLevel::Error,"create socket error ,ernno %d, %s",errno,strerror(errno));
            exit(Socket_error);
        }
        lg(Log::MsgLevel::Debug,"create socket success,%d\n",_listensock);


        int opt = 1;
        setsockopt(_listensock,SOL_SOCKET,SO_REUSEADDR | SO_REUSEPORT,&opt,sizeof(opt));

        //2.填充本地网络信息并行bind

        struct sockaddr_in local;
        memset(&local,0,sizeof(local));
        

        local.sin_family= AF_INET;
        local.sin_addr.s_addr = htonl(INADDR_ANY);
        local.sin_port = htons(_port);

        
        //进行bind
        if(bind(_listensock,conv((void*)&local),sizeof(local))!=0)
        {
            lg(Log::MsgLevel::Error,"bind error ,ernno %d, %s",errno,strerror(errno));
            exit(Bind_error);
        }
        lg(Log::Debug,"bind success\n");


        //Tcp 区别之一于Udp是需要监听的
        if(listen(_listensock,default_backlog)!=0)
        {
            lg(Log::MsgLevel::Error,"bind error ,ernno %d, %s",errno,strerror(errno));
        }
        lg(Log::Debug,"Listen socket sucess,sockfd:%d\n",_listensock);
    }    
    void Start()
    {
        std::shared_ptr<ThreadPool<std::function<void()>>> tdpool ( ThreadPool<function<void()>>::GetInstance(),
        [](void*){
            ThreadPool<std::function<void()>>::DelInstance();
        });
        tdpool->Start();
        tdpool->Detach();
        _task_func_t tmptask = std::bind(&TcpServer::DefaultService,this,std::placeholders::_1,std::placeholders::_2);
            AddTask("DefaultService",tmptask);
        _isRunning =1;

        while(_isRunning)
        {
            //获取链接
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);

            //是全双工通信的
            int sockfd = accept(_listensock,conv(&peer),&len);
            if(sockfd<0)
            {
                lg(Log::MsgLevel::Warning,"accept socket error,errno code:%d,error string,%s\n",errno,strerror(errno));
                continue;
            }
            lg(Log::MsgLevel::Debug,"accept success\n");
                
            
            InetAddr local_addr(peer);
            
            //多线程提供服务
            //-----------------------

            //这里sockfd拒绝使用引用传递，因为不知道主线程与副线程的执行情况
            //引用传递会出现覆盖而出错
            // std::thread td([this,sockfd,local_addr](){
                // Service(sockfd,local_addr);
                // Service(sockfd);
            //     close(sockfd);
            // });
            // td.detach();
            //--------------------------

            
            //线程池提供服务
            std::function<void()> task = [this,sockfd,local_addr](){
                Routine(sockfd,local_addr);
                close(sockfd);
            };
            tdpool->Push(task);

        }
    }
    std::string Read(int sockfd)
    {
        char sock_buffer[1024];
        ssize_t n = read(sockfd,sock_buffer,sizeof(sock_buffer)-1);
        if(n>0)
        {
            sock_buffer[n] = 0;

        }
        else if(n==0)//读端读取到0，就是写端关闭了，在网络就是对端关闭了链接
        {
            lg(Log::Debug,"Client quit\n");
            return "quit";
        }
        else
        {
            lg(Log::MsgLevel::Warning,"Read error,errno code:%d,error string,%s\n",errno,strerror(errno));
        }
        return sock_buffer;
    }

    void Routine(int sockfd, InetAddr addr)
    {
        _funcs["DefaultService"](sockfd,addr);  
        std::string type = Read(sockfd);
        std::string server_echo = addr.InetAddr_to_string() + " Select "+ type + "\n";
        lg(Log::Debug, "%s",server_echo.c_str());
        write(sockfd,server_echo.c_str(),server_echo.size());
        if(_funcs.find(type)!= _funcs.end())
        {
            _funcs[type](sockfd,addr);
        }
        else
        {
            lg(Log::Debug,"没有这个任务\n");
        }
        // server_echo = "执行本次任务执行完毕,输入quit退出\n";
        // write(sockfd,server_echo.c_str(),server_echo.size());
        // while(Read(sockfd)!="quit");
        return ;
    }
    void AddTask(std::string taskname,std::function<void()> task)
    {
        auto tmptask = [task](int sockfd, InetAddr addr){
            task();
        };
        _funcs[taskname] = tmptask;
    }
    void AddTask(std::string taskname,_task_func_t task)
    {
        _funcs[taskname] = task;
    }
    void DefaultService(int sockfd, InetAddr addr)
    {
        std::cout<<addr.InetAddr_to_string()<<"操作:\n";
        std::string service_list ;
        for(auto func: _funcs)
        {
            service_list +="|"+ func.first;
            service_list += "|\n";
        }
        write(sockfd, service_list.c_str(), service_list.size());
    }
    void Service(int sockfd,InetAddr addr)
    {  
        char sock_buffer[1024];
        while(1)
        {
            // dup2(sockfd,1);

            ssize_t n = read(sockfd,sock_buffer,sizeof(sock_buffer)-1);
            if(n>0)
            {
                sock_buffer[n] = 0;
                std::string client = addr.InetAddr_to_string(); 
                std::cout<<client<<"  Client Say#:"<<sock_buffer<<"\n";

                std::string echo_str = "Server return:";
                echo_str+= sock_buffer;
                write(sockfd,echo_str.c_str(),echo_str.size()+1);
            }
            else if(n==0)//读端读取到0，就是写端关闭了，在网络就是对端关闭了链接
            {
                
                lg(Log::Debug,"Client quit\n");
                break;
            }
            else
            {
                lg(Log::MsgLevel::Warning,"Read error,errno code:%d,error string,%s\n",errno,strerror(errno));
                break;
            }
        }
    }
    
    void Service(int sockfd)
    {  
        char sock_buffer[1024];
        while(1)
        {
            // dup2(sockfd,1);

            ssize_t n = read(sockfd,sock_buffer,sizeof(sock_buffer)-1);
            if(n>0)
            {
                sock_buffer[n] = 0;
                std::cout<<"Client Say#:"<<sock_buffer<<"\n";

                std::string echo_str = "Server return:";
                echo_str+= sock_buffer;
                write(sockfd,echo_str.c_str(),echo_str.size()+1);
            }
            else if(n==0)//读端读取到0，就是写端关闭了，在网络就是对端关闭了链接
            {
                
                lg(Log::Debug,"Client quit\n");
                break;
            }
            else
            {
                lg(Log::MsgLevel::Warning,"Read error,errno code:%d,error string,%s\n",errno,strerror(errno));
                break;
            }
        }
    }
};